﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.Configuration;
using System.Diagnostics;
using System.Reflection;
using System.IO;

namespace Helper
{
    public static class Helper_Log
    {
        private static object m_Locker = new object();

        /// <summary>
        /// 写日志
        /// 配置的默认格式：
        /// <!-- （高）6:OFF > 5:FATAL > 4:ERROR > 3:WARN > 2:INFO > 1:DEBUGG > 0: ALL（低）-->
        /// < add key = "LoggerLevel" value = "0" />
        /// </summary>
        /// <param name="path"></param>
        /// <param name="name"></param>
        /// <param name="content"></param>
        /// <param name="level"></param>
        private static void WriteLog(string path, string name, string content, LoggerLevel level)
        {
            //读取配置文件中配置的日志等级
            int lv = 0;

            if ((int)level < lv)
            {
                //当要记录日志的等级小于配置的日志级别时，不记录日志
                return;
            }

            if (!Check(path))
            {
                return;
            }

            //放在lock外面，避免由于等待而延时
            string logtime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
            string logdate = logtime.Substring(0, 10);
            if (!path.EndsWith("\\"))
            {
                path += "\\";
            }
            string logPath = AppDomain.CurrentDomain.BaseDirectory + @"\Log\" + path + @" " + logdate;

            StackTrace trace = new StackTrace(); //栈追踪
            StackFrame frame;   //当前线程的调用堆栈中的一个函数调用
            MethodBase method;  //函数方法

            int frame_level = 1;
            while (true)
            {
                frame = trace.GetFrame(frame_level++);//1代表上级，2代表上上级，以此类推
                method = frame.GetMethod();
                if (method.Name.ToUpper() != "OFF" &&
                    method.Name.ToUpper() != "FATAL" &&
                    method.Name.ToUpper() != "ERROR" &&
                    method.Name.ToUpper() != "WARN" &&
                    method.Name.ToUpper() != "INFO" &&
                    method.Name.ToUpper() != "DEBUGG" &&
                    method.Name.ToUpper() != "ALL")
                {
                    break;
                }
                if (frame_level > 3) { break; }
            }


            string methodname = method.Name;
            string namespacename = method.ReflectedType.Namespace;
            string classname = method.ReflectedType.Name;

            lock (m_Locker)
            {
                if (!Directory.Exists(logPath)) { Directory.CreateDirectory(logPath); }

                try
                {
                    File.AppendAllText($@"{logPath}\{name}.log", $"[{logtime}] [{Enum.GetName(typeof(LoggerLevel), level)}] - [{namespacename}] [{classname}] [{methodname}] {content}\r\n\r\n");
                }
                catch (Exception)
                {
                    //2018-07-20 Cui
                    //当人为操作日志时，比如压缩日志文件等操作，会造成文件占用，写入失败。先不做任何处理。
                }
            }
            trace = null;
            frame = null;
            method = null;
        }
        public static void SaveImg(string path, string name, byte[] bytes)
        {

            ////读取配置文件中配置的日志等级
            //int lv = 0;
            //try
            //{
            //    lv = int.Parse(ConfigurationManager.AppSettings["LoggerLevel"]);
            //}
            //catch
            //{
            //    lv = 0;
            //}

            //if ((int)level < lv)
            //{
            //    //当要记录日志的等级小于配置的日志级别时，不记录日志
            //    return;
            //}

            string logPath = AppDomain.CurrentDomain.BaseDirectory + @"\Log\" + path;
            using (MemoryStream ms = new MemoryStream(bytes))
            {
                using (FileStream fs = new FileStream($@"{logPath}\{name}.jpg", FileMode.OpenOrCreate))
                {
                    ms.WriteTo(fs);
                }
            }
        }


        public static void Debug(string path, string name, string content)
        {
            WriteLog(path, name, content, LoggerLevel.DEBUG);
        }

        public static void Info(string path, string name, string content)
        {
            WriteLog(path, name, content, LoggerLevel.INFO);
        }

        public static void Warn(string path, string name, string content)
        {
            WriteLog(path, name, content, LoggerLevel.WARN);
        }

        public static void Error(string path, string name, string content)
        {
            WriteLog(path, name, content, LoggerLevel.ERROR);
        }

        public static void Fatal(string path, string name, string content)
        {
            WriteLog(path, name, content, LoggerLevel.FATAL);
        }

        private static bool Check(string path)
        {
            if (string.IsNullOrEmpty(path.Trim()))
            {
                return false;
            }

            //获取路径和文件名的非法字符的数组
            char[] InvalidFileNameChars = Path.GetInvalidFileNameChars();
            //转成List
            List<char> list = InvalidFileNameChars.ToList();
            for (int i = list.Count - 1; i >= 0; i--)
            {
                //遍历list，去掉\\，因为路径字符串中可能包含多层路径
                if (list[i] == '\\')
                {
                    list.Remove(list[i]);
                }
            }
            //由List转成数组
            char[] c = list.ToArray();
            if (path.IndexOfAny(c) >= 0)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// (高) OFF > FATAL > ERROR > WARN > INFO > DEBUG > ALL(低)
        /// </summary>
        enum LoggerLevel
        {
            All = 0,
            DEBUG = 1,
            INFO = 2,
            WARN = 3,
            ERROR = 4,
            FATAL = 5,
            OFF = 6
        }



        public static void ClearLogDir(string path, int days)
        {
            string searchPattern = "20????????????";

            long minTime = long.Parse(DateTime.Now.AddDays(-days).ToString("yyyyMMdd000000"));

            if (Directory.Exists(path))
            {
                string[] dirs = Directory.GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);

                for (int i = 0; i < dirs.Length; i++)
                {
                    try
                    {
                        string trainComeDate = dirs[i].Substring(dirs[i].LastIndexOf(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar.ToString().Length);

                        if (trainComeDate.Length != 14)
                        {
                            continue;
                        }

                        long temp = long.Parse(trainComeDate);
                        if (temp < minTime)
                        {
                            Directory.Delete(dirs[i], true);
                        }
                    }
                    catch
                    {
                        continue;
                    }
                }
            }
        }

        public static void ClearLogFileWithHour(string path, int days)
        {
            string searchPattern = "20*.log";

            long minTime = long.Parse(DateTime.Now.AddDays(-days).ToString("yyyyMMdd"));

            string[] files = Directory.GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);

            for (int i = 0; i < files.Length; i++)
            {
                try
                {
                    string filename = files[i].Substring(files[i].LastIndexOf(Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar.ToString().Length);
                    if (filename.Length < 8 + 4)
                    {
                        continue;
                    }

                    string logDate = filename.Substring(0, 8);

                    long temp = long.Parse(logDate);
                    if (temp < minTime)
                    {
                        File.Delete(files[i]);
                    }
                }
                catch
                {
                    continue;
                }
            }
        }
    }
}
